package com.sanweibook.jhook.common.tool.excel;

import com.google.common.collect.Lists;
import com.sanweibook.jhook.common.tool.excel.annotation.Excel;
import com.sanweibook.jhook.common.tool.excel.annotation.ExcelColumn;
import com.sanweibook.jhook.common.tool.excel.handler.ExcelHandler;
import com.sanweibook.jhook.common.tool.excel.util.ValidationUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import javax.validation.ConstraintViolation;
import java.io.*;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.List;
import java.util.Set;

/**
 * Created by twg on 2017/9/9.
 */
public class DefaultExcelReadHandler<T> implements ExcelHandler {
    private static final Logger log = LoggerFactory.getLogger( DefaultExcelReadHandler.class );

    private List<DefaultExcelError> excelErrors = Lists.newArrayList();

    @Override
    public String writeExcel(List list, String fileName) {
        return null;
    }

    @Override
    public String writeExcel(Class clazz, String fileName) {
        return null;
    }

    @Override
    public void writeExcel(Class clazz, OutputStream outputStream) {

    }

    @Override
    public List readExcel(Class clazz, String fileName) {
        List result = Lists.newArrayList();
        File file = new File( fileName );
        try {
            HSSFWorkbook workbook = new HSSFWorkbook( new FileInputStream( file ) );
            int sheets = workbook.getNumberOfSheets();
            for (int i = 0; i < sheets; i++) {
                HSSFSheet sheet = workbook.getSheetAt( i );
                if (clazz.isAnnotationPresent( Excel.class )) {
                    for (int r = 1; r <= sheet.getLastRowNum(); r++) {
                        HSSFRow row = sheet.getRow( r );
                        int rowNum = row.getRowNum() + 1;
                        try {
                            T cl = (T) clazz.newInstance();
                            Field[] fields = clazz.getDeclaredFields();
                            for (Field field : fields) {
                                if (field.isAnnotationPresent( ExcelColumn.class )) {
                                    ExcelColumn excelColumn = field.getAnnotation( ExcelColumn.class );
                                    for (int c = 0; c < row.getPhysicalNumberOfCells(); c++) {
                                        HSSFCell cell = row.getCell( c );
                                        if (excelColumn.isShow() && excelColumn.columnIndex() == c) {
                                            ReflectionUtils.makeAccessible( field );
                                            if (HSSFCell.CELL_TYPE_NUMERIC == cell.getCellType()) {
                                                log.info( "This is CELL_TYPE_NUMERIC." + field.getName() );
                                            } else if (HSSFCell.CELL_TYPE_STRING == cell.getCellType()) {
                                                if (field.getGenericType().getTypeName().equals( "java.util.Date" )) {
                                                    ReflectionUtils.setField( field, cl, DateUtils.parseDate( cell.getStringCellValue(), excelColumn.dataFormat() ) );
                                                } else if (field.getGenericType().getTypeName().equals( "java.lang.Integer" )) {
                                                    ReflectionUtils.setField( field, cl, Integer.valueOf( cell.getStringCellValue() ) );
                                                } else {
                                                    ReflectionUtils.setField( field, cl, cell.getStringCellValue() );
                                                }
                                            }
                                            Set<ConstraintViolation<T>> set = ValidationUtil.getValidator().validateProperty( cl, field.getName() );
                                            if (CollectionUtils.isNotEmpty( set )) {
                                                set.forEach( constraintViolation -> {
                                                    excelErrors.add( new DefaultExcelError( rowNum, cell.getColumnIndex(), constraintViolation.getMessage() ) );
                                                } );
                                            }
                                            break;
                                        }
                                    }
                                }
                            }

                            result.add( cl );
                        } catch (InstantiationException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.getStackTrace();
        } catch (IOException e) {
            e.getStackTrace();
        }
        return result;
    }

    public List<DefaultExcelError> getExcelErrors() {
        return excelErrors;
    }
}
